package com.lwl.mini.executor.resultSet;

import com.lwl.mini.executor.ExecutorException;
import com.lwl.mini.executor.ResultMapping;
import com.lwl.mini.mapping.MapperStatement;
import com.lwl.mini.session.Configuration;
import com.lwl.mini.util.LoadingUtils;
import com.lwl.mini.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;

/**
 * @author lwl
 * @create 2022/4/19 14:18
 */
public class DefaultResultSetHandler implements ResultSetHandler {

    private final MapperStatement mapperStatement;

    private final Configuration configuration;

    public DefaultResultSetHandler(MapperStatement mapperStatement) {
        this.mapperStatement = mapperStatement;
        this.configuration = Configuration.getInstance();
    }

    @Override
    public ResultSet executeQuery(PreparedStatement stmt) {
        boolean loggedEnable = configuration.getSettings().get("loggedEnable");
        if(loggedEnable){
            System.out.println(ObjectUtils.currentTime() + " 执行语句为: " + stmt);
        }
        ResultSet result = null;
        try {
            result = stmt.executeQuery();
            if (result == null) {
                return null;
            }
            return result;
        } catch (Exception e) {
            throw new ExecutorException("sql执行阶段异常:" + e);
        }
    }


    /**
     * 处理结果集,返回最终对象
     */
    @Override
    public Object handlerResultSet(ResultSet result) throws Exception {
        List<Object> res = new ArrayList<>();
        Class<?> returnType = mapperStatement.getReturnType();
        Class aClass = null;
        if (List.class.equals(returnType)) {
            //返回结果集为List时
            aClass = classLoad(parsingType(mapperStatement.getMethod()));
        } else {
            //* 返回值类型为实体类,暂不支持map等方式作为返回值类型 *
            aClass = returnType;
        }
        //aClass = List.class.equals(returnType)?classLoad(parsingType(mapperStatement.getMethod())):returnType;
        Map<String, ResultMapping> resultMappingMap = buildResultMapping(result.getMetaData(), aClass);
        Object obj = null;
        while (result.next()) {
            obj = aClass.newInstance();
            for(String columnLabel:resultMappingMap.keySet()){
                Object value = result.getObject(columnLabel);
                Method method = resultMappingMap.get(columnLabel).getMethod();
                method.invoke(obj,value);
            }
            res.add(obj);
        }
        return res;
    }
    /**
     * 类加载返回值类路径
     */
    public Class classLoad(String classPath) {
        try {
            return LoadingUtils.getInstance().classLoad(classPath);
        } catch (ClassNotFoundException e) {
            throw new ExecutorException("类加载返回值类路径出现异常:" + e);
        }
    }

    /**
     * 若返回值为List类型，则获取method的类型，返回List的泛型
     */
    public String parsingType(Method method) {
        Type genericReturnType = method.getGenericReturnType();
        String typeName = genericReturnType.getTypeName();
        String clazz = typeName.substring(typeName.indexOf('<') + 1, typeName.indexOf('>'));
        return clazz;
    }

    /**
     * @return Map<String, ResultMapping> key为数据库列名，value为对应ResultMapping
     */
    public Map<String, ResultMapping> buildResultMapping(ResultSetMetaData metaData, Class clazz) throws SQLException {
        //key为实体类字段名称，value为实体类字段
        Map<String,Field> fieldRule = new HashMap<>();
        for (Field field : clazz.getDeclaredFields()) {
            fieldRule.put(field.getName(),field);
        }
        //key为方法名，value为对应方法
        Map<String, Method> methodRule = new HashMap<>(12);
        for (Method temp : clazz.getMethods()) {
            methodRule.put(temp.getName(), temp);
        }

        Map<String, ResultMapping> map = new HashMap<>(12);
        int columnCount = metaData.getColumnCount();
        for (int i = 1; i <= columnCount; i++) {
            String columnLabel = metaData.getColumnLabel(i);
            if (fieldRule.containsKey(columnLabel)) {
                //数据库列名包括在类中的字段
                String columnMethod = "set" + columnLabel.substring(0, 1).toUpperCase() + columnLabel.substring(1, columnLabel.length());
                if(methodRule.containsKey(columnMethod)){
                    ResultMapping resultMapping = configuration.newResultMapping(columnLabel,fieldRule.get(columnLabel), methodRule.get(columnMethod));
                    map.put(columnLabel,resultMapping);
                }
            }
        }
        return map;
    }
}
